// javamaps
// Copyright (c) 2010 Rotar Daniela
package Projection;
import Core.*;
import Data.*;

public class MercatorProjection implements IProjection {
    private IMapProvider map_;

    public MercatorProjection(){
      
    }
    public MercatorProjection(IMapProvider provider){
        map_=provider;
    }

public Point FromCoordinates(Coordinates coord, int zoomLevel){

	Point point = new Point();
	double x, y;
        double offset=0;//268435456;
	double radius=/*offset*/268435456/Math.PI;


        //x=(long0 + coord.long) * harta in pixeli  / lat hartii in coord
 

	x = (coord.Longitude() + ((map_.MapBounds()).TopLeft()).Longitude())
                * (map_.MapBounds(zoomLevel)).Width()/
                 (((map_.MapBounds()).BottomRight()).Longitude()-((map_.MapBounds()).TopLeft()).Longitude());

        // y = ln(abs( tan(lat in radiani) + 1/cos( lat in radiani)

	y =Math.log(Math.tan( Math.toRadians(coord.Latitude())) +
                   1.0/Math.cos(Math.toRadians(coord.Latitude())));
//                  (map_.MapBounds(zoomLevel)).Height()/
//                  (((map_.MapBounds()).TopLeft()).Latitude()-((map_.MapBounds()).BottomRight()).Latitude());
////        y =Math.log(Math.tan( coord.Latitude()) +
////                   1.0/Math.cos(coord.Latitude())) *
////                  (map_.MapBounds(zoomLevel)).Height()/
////                  (((map_.MapBounds()).TopLeft()).Latitude()-((map_.MapBounds()).BottomRight()).Latitude());
//
////        y = 0.5 * Math.log((1.0 + Math.sin(coord.Latitude()))/(1.0 - Math.sin(coord.Latitude())))
////                *(map_.MapBounds(zoomLevel)).Height()/
////                  (((map_.MapBounds()).TopLeft()).Latitude()-((map_.MapBounds()).BottomRight()).Latitude());
//
//        y = Math.round(offset - radius *
//                Math.log((1 + Math.sin(coord.Latitude() * Math.PI / 180)) /
//                (1 - Math.sin(coord.Latitude() * Math.PI / 180))) / 2)
//                //Math.round(offset-radius*Math.log((1+Math.sin(coord.Latitude()*Math.PI/180))/(1-Math.sin(coord.Latitude()*Math.PI/180)))/2);
//                //Math.round(radius*Math.log((1+Math.sin(coord.Latitude()*Math.PI/180))/(1-Math.sin(coord.Latitude()*Math.PI/180)))/2);
//            *Math.abs((map_.MapBounds(zoomLevel)).Height()/
//                 (((map_.MapBounds()).TopLeft()).Latitude()-((map_.MapBounds()).BottomRight()).Latitude()));
//
//
        y = (coord.Latitude() + ((map_.MapBounds()).TopLeft()).Latitude())
                * (map_.MapBounds(zoomLevel)).Width()/
                 (((map_.MapBounds()).BottomRight()).Longitude()-((map_.MapBounds()).TopLeft()).Longitude());


	point.SetX(x);
	point.SetY(y);

	return point;


}


    public Coordinates ToCoordinates(Point point, int zoomLevel){

         double offset=268435456;
	double radius=offset/Math.PI;

	Coordinates coord=new Coordinates();
	double latitudine,longitudine;

     
	longitudine = ((map_.MapBounds()).TopLeft()).Longitude() +
                point.X() * (((map_.MapBounds()).BottomRight()).Longitude()-((map_.MapBounds()).TopLeft()).Longitude())/
                            (map_.MapBounds(zoomLevel)).Width();
	
//        latitudine = Math.atan( Math.sinh(point.Y()))*
//                (((map_.MapBounds()).TopLeft()).Latitude()-((map_.MapBounds()).BottomRight()).Latitude())/
//                (map_.MapBounds(zoomLevel)).Height();

      // latitudine = -(Math.PI/2-2*Math.atan(Math.exp((Math.round(point.Y())))/radius))*180/Math.PI;
        latitudine = ((map_.MapBounds()).TopLeft()).Latitude() +
                point.Y() * (((map_.MapBounds()).BottomRight()).Latitude()-((map_.MapBounds()).TopLeft()).Latitude())/
                            (map_.MapBounds(zoomLevel)).Height();
	coord.SetLongitude(longitudine);
	coord.SetLatitude(latitudine);

	return coord;

}


    public Region2D FromRegion(Region region, int zoomLevel){
        
        Point point1 = new Point(FromCoordinates(region.TopLeft(), zoomLevel));
        Point point2 = new Point(FromCoordinates(region.BottomRight(), zoomLevel));
        Region2D region2D = new Region2D(Region2D.FromPoints(point1, point2));
        
       
        return region2D;
    };
    public Region FromRegion2D(Region2D region, int zoomLevel){
        Point point1 = new Point(region.Left(),region.Top());
        Point point2 = new Point(region.Right(),region.Bottom());
        Coordinates coord1 = new Coordinates(ToCoordinates(point1, zoomLevel));
        Coordinates coord2 = new Coordinates(ToCoordinates(point2, zoomLevel));
        Region region2 = new Region(coord1,coord2);

        return region2;
    };
}